﻿using Dyao.Book.Contract;
using Dyao.Book.Entity;
using Dyao.Repository.Abstractions;

namespace Dyao.Book.Repository
{
    using Foundation.Replacement;

    public class TaskCenterRecordRepository : DataRepository<TaskCenterRecordEntity, int>, ITaskCenterRecordRepository
    {
        /// <summary>
        /// 获取重试列表
        /// </summary>
        /// <param name="pageIndex">pageIndex</param>
        /// <param name="pageSize">pageSize</param>
        /// <param name="cancellationToken">cancellationToken</param>
        /// <returns></returns>
        public async Task<List<TaskCenterRecordEntity>> GetNeedRetryListAsync(int pageIndex, int pageSize, CancellationToken cancellationToken = default)
        {
            var queryable = GetQueryable().Where(m => m.RetryCountMax > m.RetryCount
                                                  && (m.Status == TaskCenterRecordStatusEnum.Excuting
                                                    || m.Status == TaskCenterRecordStatusEnum.ExcuteFail));
            return await queryable.OrderByDescending(m => m.ID).Skip(pageIndex * pageSize).Take(pageSize).ToListAsync(cancellationToken);
        }

        /// <summary>
        /// 获取超时列表
        /// </summary>
        /// <param name="pageIndex">pageIndex</param>
        /// <param name="pageSize">pageSize</param>
        /// <param name="cancellationToken">cancellationToken</param>
        /// <returns></returns>
        public async Task<List<TaskCenterRecordEntity>> GetTimeoutListAsync(int pageIndex, int pageSize, CancellationToken cancellationToken = default)
        {
            var queryable = GetQueryable().Where(m => m.RetryCountMax == m.RetryCount
                                                   && m.Status == TaskCenterRecordStatusEnum.Excuting);
            return await queryable.OrderByDescending(m => m.ID).Skip(pageIndex * pageSize).Take(pageSize).ToListAsync(cancellationToken);
        }

        /// <summary>
        /// 获取已完成状态的任务记录Id列表 用于删除
        /// </summary>
        /// <param name="recordTypeEnum">记录类型</param>
        /// <param name="maxDateTime"></param>
        /// <param name="num">数量</param>
        /// <param name="cancellationToken"></param>
        /// <returns>记录数据主键Id列表</returns>
        public async Task<List<int>> GetCompleteTaskRecordIdListForDeleteAsync(DeleteRecordTypeEnum recordTypeEnum, DateTime maxDateTime, int num = 500, CancellationToken cancellationToken = default)
        {
            var queryable = GetQueryable().Where(m => m.CreateDateTime <= maxDateTime);
            switch (recordTypeEnum)
            {
                case DeleteRecordTypeEnum.Complete:
                    queryable = queryable.Where(m => m.Status == TaskCenterRecordStatusEnum.ExcuteSuccess
                                                  || (m.Status == TaskCenterRecordStatusEnum.ExcuteFail && m.RetryCountMax == 0));
                    break;
                case DeleteRecordTypeEnum.RetryCount:
                    queryable = queryable.Where(m => m.Status == TaskCenterRecordStatusEnum.ExcuteFail
                                                  && m.RetryCountMax > 0);
                    break;
            }
            return await queryable.Select(m => m.ID).OrderBy(m => m).Take(num).ToListAsync(cancellationToken);
        }

        /// <summary>
        /// 根据属性名更新属性值
        /// </summary>
        /// <param name="task">任务</param>
        /// <param name="propertyNames">属性名称</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns></returns>
        public Task UpdateByPropertyNameAsync(TaskCenterRecordEntity task, string[] propertyNames, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var entity = DbSet.Local.FirstOrDefault(a => a.ID == task.ID);
            if (entity != null)
            {
                var orgEntry = this.DbSet.Attach(entity);
                orgEntry.State = Microsoft.EntityFrameworkCore.EntityState.Detached;
            }

            var entry = DbSet.Attach(task);
            var rowVersionName = nameof(TaskCenterRecordEntity.RowVersion);
            foreach (var propertyName in propertyNames.Where(a => rowVersionName != a))
            {
                var property = entry.Property(propertyName);
                if (property != null)
                {
                    property.IsModified = true;
                }
            }

            //entry.State = EntityState.Modified;

            return Task.CompletedTask;
        }

        #region  // override methods

        public override async Task<TaskCenterRecordEntity> InsertAsync(TaskCenterRecordEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            CompletedAppKey(entity);

            return await base.InsertAsync(entity, autoSave, cancellationToken);
        }

        public override async Task InsertRangeAsync(IEnumerable<TaskCenterRecordEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            foreach (var entity in entities)
            {
                CompletedAppKey(entity);
            }

            await base.InsertRangeAsync(entities, autoSave, cancellationToken);
        }

        protected void CompletedAppKey(TaskCenterRecordEntity entity)
        {
            if (string.IsNullOrWhiteSpace(entity.AppKey))
            {
                entity.AppKey = "DyaoBook";
            }
        }

        #endregion  // end override methods
    }
}
